import CheckBox from "@lib/CheckBox";
import { IsNotNullOrUndefined } from "@lib/helper";
import Slot, { type Slots } from "@lib/Slot";
import Loading from "@lib/Spinner/loading";
import {
  type ParentProps,
  splitProps,
  mergeProps,
  createMemo,
  createSignal,
  createEffect,
  on,
  type Accessor,
  type JSX,
  Show,
} from "solid-js";
import TableBody from "./TableBody";
import TableCaption from "./TableCaption";
import TableFooter from "./TableFooter";
import TableHeader from "./TableHeader";
import type {
  TableProps,
  TableEvents,
  TableSlots,
  Indexed,
  TableColumnProps,
} from "./types";
import { hasNumberWidth, wrappedStickyStyle } from "./utils";
import { wrapClasses } from "@lib/types";
import EmptyContent from "@lib/empty/EmptyContent";

const INDEX_KEY = "__index__";

const defaultTableProps: Partial<TableProps<any>> = {
  columns: [],
  datas: [],
  rowKey: INDEX_KEY,
  responsive: true,
  captionHeight: 40,
};

const InternalTable = <T = {},>(
  p: ParentProps<TableProps<T> & TableEvents<T> & Slots<TableSlots>>
) => {
  const [local, props] = splitProps(mergeProps(defaultTableProps, p), [
    "children",
    "columns",
    "rowKey",
    "selected",
    "datas",
    "classList",
    "fixedHeader",
    "style",
    "nowrap",
    "slots",
    "captionTop",
    "captionHeight",
    "emptyContent",
    "responsive",
    "tableClassList",
  ]);

  const datas = createMemo(() => {
    return (
      local.datas?.map((d, i) => {
        return {
          ...d,
          [INDEX_KEY]: i,
        };
      }) ?? []
    );
  });

  const getRowKey = (data: T, index: number) => {
    if (IsNotNullOrUndefined(local.rowKey)) {
      if (typeof local.rowKey === "string") {
        return (data as { [key: string]: any })[local.rowKey!];
      } else {
        return local.rowKey(data);
      }
    }
    console.warn("没有指定RowKey");
    return index;
  };

  const [_selected, _setSelected] = createSignal<Indexed<T>[]>([]);
  const selectedIndex = createMemo(() => {
    return _selected().reduce((p, c) => {
      const rowKey = getRowKey(c, c.__index__);
      if (IsNotNullOrUndefined(rowKey)) {
        p.push(rowKey);
      }
      return p;
    }, [] as any[]);
  });

  // createEffect(
  //   on(datas, (v) => {
  //     _setSelected([]);
  //   })
  // );

  createEffect(
    on(_selected, (v) => {
      props.onSelect?.(v);
    })
  );

  const handleRowSeleted = (data: T, index: number, selected: boolean) => {
    const rowKey = getRowKey(data, index);

    if (selected) {
      // Append
      _setSelected((c) => [...c, { ...(data as any) }]);
    } else {
      // Remove
      _setSelected((c) =>
        c.filter((d) => getRowKey(d, d.__index__) !== rowKey)
      );
    }
  };

  const handleSelectedAll = (selected: boolean) => {
    if (selected) {
      _setSelected(datas() ?? []);
    } else {
      _setSelected([]);
    }
  };
  const getDataSelected = (data: T, index: number) => {
    const selected = selectedIndex().includes(getRowKey(data, index));
    // console.log('index', index, 'selected', selected)
    return selected;
  };

  const columns = createMemo(() => {
    const d = {
      left: 0,
      right: 0,
    };

    return local.columns
      ?.map((col) => {
        if (col.type == "index") {
          const indexColumn: TableColumnProps<T> = {
            fixed: "left",
            width: 40,
            children: (_a, _b, index) => index + 1,
            label: "#",
            headerAlign: "center",
            align: "center",
            ...col,
          };
          return indexColumn;
        } else if (col.type === "selection") {
          const selectionColumn: TableColumnProps<T> = {
            fixed: "left",
            width: 32,
            children: (data: T, column: TableColumnProps<T>, index: number) => (
              <CheckBox
                value={getDataSelected(data, index)}
                onChange={(v) => handleRowSeleted(data, index, v)}
              ></CheckBox>
            ),
            label: (
              <CheckBox
                value={
                  _selected().length > 0 &&
                  _selected().length === datas().length
                }
                onChange={(v) => handleSelectedAll(v)}
              ></CheckBox>
            ),
            ...col,
          };

          return selectionColumn;
        } else {
          return col;
        }
      })
      .map((col) => {
        const has = hasNumberWidth(col);

        if (has) {
          if (col.fixed === "left") {
            d.left += col.width as number;
          }

          if (col.fixed === "right") {
            d.right += col.width as number;
          }
        }

        wrappedStickyStyle(col, d);

        return {
          ...col,
          classList: {
            // 计算固定列
            fixed: has && col.fixed !== undefined,
            "fixed-left": has && col.fixed === "left",
            "fixed-right": has && col.fixed === "right",
            ...col.classList,
          },
        };
      });
  });

  const tableContainerClassList = createMemo(() => {
    return {
      "table-responsive": local.responsive,
    };
  });

  const tableClassList: Accessor<JSX.CustomAttributes<any>["classList"]> =
    createMemo(() => {
      return {
        "table-hover": props.hover,
        "table-bordered": props.border === "bordered",
        "table-borderless": props.border === "borderless",
        "table-primary": props.variants === "primary",
        "table-secondary": props.variants === "secondary",
        "table-success": props.variants === "success",
        "table-danger": props.variants === "danger",
        "table-warning": props.variants === "warning",
        "table-info": props.variants === "info",
        "table-light": props.variants === "light",
        "table-dark": props.variants === "dark",
        "table-striped": props.striped === "striped",
        "table-striped-columns": props.striped === "striped-columns",
        "table-sm": props.size === "sm",
        "table-fixed-header": local.fixedHeader,
        "table-nowrap": local.nowrap,
        "caption-top": local.captionTop,
        ...wrapClasses(local.tableClassList),
      };
    });

  const hasDatas = createMemo(() => {
    return (local.datas ?? []).length;
  });

  return (
    <div
      style={local.style}
      class="table-border"
      classList={{ ...tableContainerClassList(), ...local.classList }}
    >
      <table class="table" classList={tableClassList()}>
            <Slot
              slot={local.slots?.header}
              context={{
                fixed: local.fixedHeader,
                columns: columns(),
                style: {
                  top:
                    IsNotNullOrUndefined(props.caption) &&
                    local.fixedHeader &&
                    local.captionTop &&
                    local.captionHeight !== undefined
                      ? `${local.captionHeight}px`
                      : undefined,
                },
              }}
            >
              {TableHeader}
            </Slot>
            <Slot
              slot={local.slots?.body}
              context={{
                columns: columns(),
                datas: datas(),
                emptyContent: local.emptyContent,
              }}
            >
              {TableBody}
            </Slot>
            <Slot
              slot={local.slots?.footer}
              context={{
                columns: columns(),
                datas: local.datas,
                style: {
                  bottom:
                    IsNotNullOrUndefined(props.caption) &&
                    !local.captionTop &&
                    local.captionHeight !== undefined
                      ? `${local.captionHeight}px`
                      : undefined,
                },
              }}
            >
              {TableFooter}
            </Slot>
            <Show when={local.captionHeight !== undefined}>
              <Slot
                slot={local.slots?.caption}
                context={{
                  children: IsNotNullOrUndefined(props.caption) ? (
                    <div class="caption-content ps-2 pe-2">{props.caption}</div>
                  ) : undefined,
                }}
              >
                {TableCaption}
              </Slot>
            </Show>
          </table>
          <Show when={!hasDatas()}>
            <EmptyContent>{local.emptyContent}</EmptyContent>
          </Show>

      {/* <Loading show={local.loading} spinner={local.loadingContent}>
        <div
          class="table-container d-flex flex-column h-100 w-100"
          classList={{
            ...tableContainerClassList(),
            "align-items-start": local.responsive,
          }}
        >

        </div>
      </Loading> */}
    </div>
  );
};

export default InternalTable;
